<!DOCTYPE html>
<html lang="en">
<head>
    <script src="/static/js/dev.js"></script>
    <meta charset="UTF-8">
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <!--bootstrap插件-->
    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
    <link href="/static/plugin/bootstrap/bootstrap-3.3.7-dist/css/bootstrap.min.css" rel="stylesheet"/>
    <link href="/static/plugin/jo/joUI.css" rel="stylesheet"/>
    <!--字体插件-->
    <link href="/static/plugin/font-awesome-4.7.0/css/font-awesome.min.css" rel="stylesheet"/>
    <link href="/static/plugin/layui-2.4.3/css/layui.css" rel="stylesheet"/>
    <!--ztree-->
    <link href="/static/plugin/zTree/css/metroStyle/metroStyle.css" rel="stylesheet"/>
    <!--common-->
    <link href="/static/css/common.css" rel="stylesheet"/>

    <title>链路图</title>
    <style type="text/css">
        .api-line-box {
            width: 100%;
        }

        .api-line-standard {
            width: 100%;
            height: 4px;
            background-color: #666666;
            position: relative;
            margin-bottom: 5px;
        }

        .api-line-time-point {
            width: 10px;
            height: 10px;
            border-radius: 5px;
            background-color: #FFFFFF;
            position: absolute;
            border: #37A2DA solid 1px;
            top: -3px;
            cursor: pointer;
        }

        .api-line-time-point:hover {
            -webkit-box-shadow: 0 0 5px rgba(0, 113, 241, 1);
        }

        .api-line-row {
            position: relative;
            height: 22px;
            margin: 2px 0px;
        }

        .api-line {
            height: 22px;
            line-height: 22px;
            padding: 0px 3px;
            border: #000000 solid 1px;
            text-align: left;
            position: absolute;
            color: #EFEFEF;
            overflow: hidden;
            white-space: nowrap;
            text-overflow: ellipsis;
            cursor: default;
            border-radius: 4px;
        }

        .api-line:hover {
            font-weight: 600;
        }

        .api-line-active {
            font-weight: 600;
            -webkit-box-shadow: 0 0 5px rgba(0, 113, 241, 1);
        }

        /*标题*/
        .part-title {
            font-weight: 700;
            line-height: 20px;
            border-bottom: #448AFF solid 2px;
            margin-bottom: 8px;
            clear: both;
            font-size: 16px;
        }

        /*选中的行*/
        .trace-choice-active {
            border: #E690D1 solid 1px;
        }
    </style>
</head>
<body class="skin-default">
<div class="container-fluid">
    <div class="row">
        <div class="col-xs-12">
            <!--视图块-->
            <div class="container-fluid card">
                <div class="row">
                    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                        <div class="part-title">链路时间分布:</div>
                        <div class="api-line-box">
                            <div class="api-line-standard"></div>
                            <!-- <div class="api-line-standard">
                                <div class="api-line-time-point" title="2019-09-19 11:11:11.222"></div>
                            </div>
                            <div class="api-line-row">
                                <div class="api-line" style="width: 50px;left: 60px;">123</div>
                                <div class="api-line" style="width: 80px;left: 120px;">345</div>
                            </div> -->
                        </div>

                    </div>
                </div>

                <div class="row">
                    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
                        <div class="part-title">链路日志:</div>
                        <table class="table table-bordered table-hover table-line-auto" id="mainList"
                               trHandle="trHandle" titleCss="jo-view-table-header" >
                            <col field="_seq" title="#" width="50px" align="center"/>
                            <col field="{exShow}" title="" width="50px" align="center"/>
                            <col field="{keyInfo} <br> {shortKey}" title="方法" width="30%" align=""
                                 tips="{keyInfo} #{key} @{appName}"/>
                            <!--                            <col field="{shortKey}" title="方法路径" width="20%" align=""  tips="{className}.{methodName}" />-->
                            <!--                            <col field="{appName}" title="应用" width="10%" align=""  tips="keyInfo" />-->
                            <col field="userShow" title="用户" width="10%" align=""/>
                            <!-- <col field="execTimeShow" title="执行时间" width="15%" align=""/> -->
                            <col field="[=jo.formatTimestamp('{beginTime}')]" title="开始时间" width="15%" align=""
                                 order="beginTime"/>
                            <col field="[=jo.formatTimestamp('{endTime}')]" title="结束时间" width="15%" align=""
                                 order="endTime"/>
                            <col field="ms" title="耗时/ms" width="8%" align="right" order="ms"/>
                            <col field="serverIp" title="服务器IP" width="10%" align=""/>
                            <col field="_opt" title="" width="50px" align="center"/>
                            <!--<col field="userId" title="用户id" width="15%" align=""  />-->
                        </table>
                    </div>
                </div>

            </div>

        </div>
    </div>
</div>


<!--配置信息-->
<script src="/static/js/config.js"></script>
<!--jquery-->
<script src="/static/plugin/jquery/jquery-3.3.1.js"></script>
<script src="/static/plugin/jquery/jquery.cookie.js"></script>
<!--bootstrap-->
<script src="/static/plugin/bootstrap/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<!--[if lt IE 9]>
<script src="/static/plugin/other/html5shiv.js"></script>
<script src="/static/plugin/other/respond.min.js"></script>
<![endif]-->
<!--layui-->
<script src="/static/plugin/layui-2.4.3/layui.all.js"></script>
<!--ztree-->
<script src="/static/plugin/zTree/js/jquery.ztree.all.js"></script>
<!--common-->
<script src="/static/js/common.js"></script>
<!--jo-->
<script src="/static/plugin/jo/jo.js"></script>
<script src="/static/plugin/jo/jo-adapt.js"></script>
<script src="/static/plugin/jo/jo-page-view.js"></script>
<script src="/static/plugin/jo/jo-page-form.js"></script>
<script src="/static/plugin/jo/jo-listener.js"></script>
<script type="text/javascript">
    //行处理
    function trHandle(item, idx) {
        item.exShow = item.hasEx ? '<span class="fa fa-circle font-red"></span>' : '<span class="fa fa-circle font-green"></span>';
        item.userName = jo.getDefVal(item.userName, '');
        item.userId = jo.getDefVal(item.userId, '');
        if (item.userName) {
            item.userShow = item.userName;
        }
        if (item.userId) {
            item.userShow = item.userShow ? (item.userShow + '<br>ID: ' + item.userId) : ('ID: ' + item.userId);
        }
        if (item.key) {
            var arr = item.className.split('.');
            for (var i = 0; i < arr.length - 1; i++) {
                arr[i] = arr[i].charAt(0);
            }
            item.shortKey = arr.join('.') + '.' + item.methodName;
        }
        if (item.id == jo.getUrlParam('id')) {
            item['_style'] = 'font-weight: 700;';
        }
        item._opt = '<a class="fa fa-file-text-o cursor-hand" title="点击查看详情" onclick="parent.jo.showWin(\'/page/monitor/traceForm.html?id=' + item.id + '\', \'780px\', \'70%\', \'方法详情\');"></a>';

        //item.execTimeShow = jo.formatTimestamp(item.beginTime) + '<br>' + jo.formatTimestamp(item.endTime);
    }

    var traceId = jo.getUrlParam('traceId');//'8b588190e1d34db688e0dbab6542bf6e';//链路id
    if (traceId) {
        jo.postAjax('{URL_MONITOR}monitor/apiTrace/getListByTraceId?traceId=' + traceId, {}, function (json) {
            if (json && json.code == 0 && json.data && json.data.length > 0) {
                timeLineChart(json.data);
            }
        }, true);
    }
    //点击高亮
    $('.api-line-box').on('click', '.api-line', function () {
        $('.api-line-box .api-line').removeClass('api-line-active');
        $(this).addClass('api-line-active');
    });

    //监控方法对象
    function MonitorMethod(apiTrace) {
        this.key = apiTrace.key;
        this.name = apiTrace.keyInfo;
        this.traceId = apiTrace.traceId;
        this.lineLength = apiTrace.endTime - apiTrace.beginTime;//耗时长短
        this.apiTrace = apiTrace;
        this.subMethod = [];//子方法
        //判断入参时间点是否在方法执行时间区间内
        this.include = function (time, end) {
            return time >= this.apiTrace.beginTime && time <= this.apiTrace.endTime
                && (!end || (end >= this.apiTrace.beginTime && end <= this.apiTrace.endTime));
        };
    }

    //时间线图
    function timeLineChart(arr) {
        var methodArr = [];//1级方法数组,通常是单个
        //按照开始时间排序
        jo.sort(arr, function (a, b) {
            if (a.beginTime == b.beginTime) {
                return a.endTime > b.endTime;
            }
            return a.beginTime < b.beginTime;
        });
        //刷新表格
        Grid('mainList').loadData(arr);
        console.info(arr);
        //找出时间起止
        var beginTime = null;
        var endTime = null;
        for (var i = 0; i < arr.length; i++) {
            var item = arr[i];
            if (!beginTime || item.beginTime < beginTime) {
                beginTime = item.beginTime;//记录更小的开始时间
            }
            if (!endTime || item.endTime > endTime) {
                endTime = item.endTime;
            }
        }
        var totalLength = endTime - beginTime;//时间总线长度

        //组装时间线
        var lineArr = [[new MonitorMethod(arr[0])]];//[[a, b], [c, d]]
        out:
            for (var i = 1; i < arr.length; i++) {
                var item = arr[i];
                row:
                    for (var j = 0; j < lineArr.length; j++) {
                        var lines = lineArr[j];//第j行的方法集合
                        one:
                            for (var m = 0; m < lines.length; m++) {
                                var line = lines[m];//第j行的第m个方法
                                if (line.include(item.beginTime, item.endTime)) {//item开始时间在当前方法线范围内,另起一行
                                    if (j >= (lineArr.length - 1)) {//已经是最后一行的,则新建一行, 然后开始执行下一个
                                        lineArr.push([new MonitorMethod(item)]);
                                        continue out;
                                    } else {
                                        continue row;//不到最后一行,则去下一行找爸爸
                                        // continue one;
                                    }
                                } else {
                                    if (m >= (lines.length - 1)) {//已经是本行的最后一条线,加入本行, 然后开始执行下一个
                                        lines.push(new MonitorMethod(item));
                                        continue out;
                                    } else {//没到这行的最后一个,则继续走这一行的下一个
                                        continue one;
                                    }
                                }
                            }

                    }
            }
        console.info(lineArr);

        var color = ['#37A2DA', '#32C5E9', '#67E0E3', '#9FE6B8', '#FFDB5C', '#FF9F7F', '#FB7293', '#E062AE', '#E690D1', '#E7BCF3', '#9D96F5', '#8378EA', '#96BFFF'];//调色板
        //开始画线
        var allWidth = $('.api-line-box').width();
        //var _html = '<div class="api-line-standard"></div>';
        var pointArr = {};//基线上的时间点
        //pointArr.push({time: beginTime, width: 0});//起点
        pointArr[beginTime] = 0;//起点
        pointArr[endTime] = allWidth;//终点
        //pointArr.push({time: endTime, width: allWidth});//终点
        for (var i = 0; i < lineArr.length; i++) {
            var lines = lineArr[i];
            var _html = '<div class="api-line-row">';
            for (var j = 0; j < lines.length; j++) {
                var line = lines[j];
                var w = parseInt(allWidth * (line.lineLength / totalLength));//宽度
                var l = parseInt(allWidth * ((line.apiTrace.beginTime - beginTime) / totalLength));//距左
                //pointArr.push({time: line.apiTrace.beginTime, width: l});
                //pointArr.push({time: line.apiTrace.endTime, width: l+w});
                pointArr[line.apiTrace.beginTime] = l;
                pointArr[line.apiTrace.endTime] = l + w;
                if (w < 10) {
                    w = 10;
                }
                _html += '<div id="api-line-' + i + '-' + j + '" class="api-line"' +
                    ' style="width: ' + w + 'px;left: ' + l + 'px;background-color: ' + color[i % color.length] + ';display:none;"' +
                    ' title="' + line.name + ' -耗时:' + line.lineLength + 'ms">'
                    + line.name + ' <small>(' + line.key + ') -耗时:' + line.lineLength + 'ms</small>' +
                    '</div>';
            }
            _html += '</div>';
            $('.api-line-box').append(_html);
            for (var j = 0; j < lines.length; j++) {
                $('#api-line-' + i + '-' + j).fadeIn(i * 1000 + j * 500 + 500);
            }
        }


        //基线画点
        for (var k in pointArr) {
            var w = pointArr[k];
            var _html = '<div id="point_' + k + '" class="api-line-time-point" title="" style="left: ' + (w - 4) + 'px;" onmouseover="window.tipsIdx=jo.tips(\'' + jo.formatTimestamp(k) + '\', this, {tips:3});" onmouseout="jo.close(window.tipsIdx);"></div>';
            $('.api-line-standard').append(_html);
        }
    }
</script>

</body>
</html>
